package br.com.news.service;

import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import br.com.news.activity.json.Http;
import br.com.news.activity.json.Http.ConnectionType;
import br.com.news.activity.json.ParseJson;
import br.com.news.dao.CategoriaDao;
import br.com.news.dao.interfaces.ICategoriaDao;
import br.com.news.exception.ConnectionException;
import br.com.news.exception.DataException;
import br.com.news.exception.NoResultException;
import br.com.news.exception.ServiceException;
import br.com.news.modal.CategoriaBean;
import br.com.news.service.interfaces.ICategoriaService;
import br.com.news.util.CollectionUtils;
import br.com.news.util.Constantes;

import com.google.gson.reflect.TypeToken;

public class CategoriaService implements ICategoriaService {

	private ICategoriaDao categoriaDao;

	public CategoriaService(Context context) {
		categoriaDao = new CategoriaDao(context);
	}

	@Override
	public long salvar(CategoriaBean categoriaBean) throws ServiceException {
		try {
			return categoriaDao.salvar(categoriaBean);
		} catch (DataException e) {
			throw new ServiceException(String.format("<CategoriaService> Falha ao salvar registro %d", categoriaBean.getId()), e);
		}
	}

	@Override
	public void atualizar(CategoriaBean categoriaBean) throws ServiceException {
		try {
			categoriaDao.atualizar(categoriaBean);
		} catch (DataException e) {
			throw new ServiceException(String.format("<CategoriaService> Falha ao atualizar registro %d", categoriaBean.getId()), e);
		}
	}

	@Override
	public long inserir(CategoriaBean categoriaBean) throws ServiceException {
		try {
			return categoriaDao.inserir(categoriaBean);
		} catch (DataException e) {
			throw new ServiceException(String.format("<CategoriaService> Falha ao inserir registro %d", categoriaBean.getId()), e);
		}
	}

	@Override
	public int deletar(long idCategoria) throws ServiceException {
		try {
			return categoriaDao.deletar(new CategoriaBean(idCategoria));
		} catch (DataException e) {
			throw new ServiceException(String.format("<CategoriaService> Falha ao deletar registro %d", idCategoria), e);
		}
	}

	@Override
	public CategoriaBean findId(long idCategoria) throws ServiceException {
		try {
			return categoriaDao.findId(new CategoriaBean(idCategoria));
		} catch (DataException e) {
			throw new ServiceException(String.format("<CategoriaService> Falha ao buscar registro pelo id %d", idCategoria), e);
		}
	}

	@Override
	public List<CategoriaBean> findAll() throws ServiceException {
		try {
			return categoriaDao.findAll(new CategoriaBean());
		} catch (DataException e) {
			throw new ServiceException("<CategoriaService> Falha ao buscar todos os registro", e);
		}
	}

	@Override
	public void fechar() {
		categoriaDao.fechar();
	}

	@Override
	public List<CategoriaBean> buscaCategoriasSelecionadas() throws ServiceException, NoResultException {
		try {
			List<CategoriaBean> categoriaBeans = categoriaDao.buscaCategoriasPorSelecionada(true);
			if (CollectionUtils.isEmpty(categoriaBeans))
				throw new NoResultException("<CategoriaService> Nenhuma categoria foi selecionada.");
			return categoriaBeans;
		} catch (DataException e) {
			throw new ServiceException("<CategoriaService> Falha ao buscar categorias selecionadas.", e);
		}
	}

	@Override
	public void sincronizar() throws ServiceException {
		try {
			Reader reader = Http.connection(ConnectionType.GET, Constantes.URL_CATEGORIA_ATIVA, null);
			List<CategoriaBean> categoriaBeans = (new ParseJson<CategoriaBean>()).parseObjectList(new TypeToken<List<CategoriaBean>>() {}.getType(), reader);
			List<CategoriaBean> beans = categoriaDao.findAll(new CategoriaBean());
			sincronizaObjetos(categoriaBeans, beans);
		} catch (ConnectionException e) {
			throw new ServiceException("<CategoriaService> Falha ao sincronizar as categorias com o servidor!", e);
		} catch (DataException e) {
			throw new ServiceException("<CategoriaService> Falha ao salvar categorias sincronizadas!", e);
		}
	}
	
	/**
	 * Realiza as alterações nas categorias com base sincronizadas
	 * 
	 * @param categoriaBeans
	 * @param beans
	 * @throws DataException
	 */
	private void sincronizaObjetos(List<CategoriaBean> categoriaBeans, List<CategoriaBean> beans) throws DataException{
		List<CategoriaBean> listaAtualizar = new ArrayList<CategoriaBean>();
		List<CategoriaBean> listaInserir = new ArrayList<CategoriaBean>(categoriaBeans);
		List<CategoriaBean> listaDeletar = new ArrayList<CategoriaBean>(beans);
		for (CategoriaBean bean : beans) {
			for (CategoriaBean categoriaBean : categoriaBeans) {
				if (bean.equals(categoriaBean)) {
					bean.setDescricao(categoriaBean.getDescricao());
					listaAtualizar.add(bean);
					listaDeletar.remove(bean);
					listaInserir.remove(categoriaBean);
				}
			}
		}
		atualizarCategorias(listaAtualizar);
		inserirCategorias(listaInserir);
		detetarCategorias(listaDeletar);
	}
	
	/**
	 * Altera catagorias sincronizadas
	 * 
	 * @param listaAtualizar
	 * @throws DataException
	 */
	private void atualizarCategorias(List<CategoriaBean> listaAtualizar) throws DataException{
		for (CategoriaBean categoriaBean : listaAtualizar) {
			categoriaDao.atualizar(categoriaBean);
		}
	}
	
	/**
	 * Deleta categorias que não estão ativas no servidor
	 * 
	 * @param beans
	 * @throws DataException
	 */
	private void detetarCategorias(List<CategoriaBean> beans) throws DataException{
		for (CategoriaBean categoriaBean : beans) {
			categoriaDao.deletar(categoriaBean);
		}
	}
	
	/**
	 * Inseri categorias novas do servidor
	 * @param categoriaBeans
	 * @throws DataException
	 */
	private void inserirCategorias(List<CategoriaBean> categoriaBeans) throws DataException{
		for (CategoriaBean categoriaBean : categoriaBeans) {
			categoriaDao.inserir(categoriaBean);
		}
	}
}
